package cn.sgy.infrastructure.file.strategy;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.StrPool;
import cn.hutool.crypto.digest.DigestUtil;
import cn.sgy.infrastructure.file.entity.File;
import cn.sgy.infrastructure.file.util.FileDataTypeUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Date;

/**
 * @author sgy
 * @description 抽象类
 * @date 2023-11-17
 */
@Slf4j
public abstract class AbstractFileStore implements FileStore {
    @Override
    public File upload(MultipartFile mf) {
        // 非空检查
        if (mf == null || mf.isEmpty()) {
            throw new IllegalArgumentException("MultipartFile不允许为空");
        }
        // 根据参数构建file对象
        File file = buildFile(mf);
        // 模板方法子类实现
        doUpload(file, mf);
        return file;
    }

    /**
     * 先构建一部分属性的File对象
     *
     * @param mf MultipartFile
     * @return file
     */
    @SneakyThrows
    private File buildFile(MultipartFile mf) {
        InputStream inputStream = mf.getInputStream();
        String fileExtName = FileNameUtil.extName(mf.getOriginalFilename());
        String fileName = buildFileName(fileExtName);
        File file = new File(
                mf.getOriginalFilename(),
                fileName,
                fileExtName,
                mf.getSize(),
                DigestUtil.md5Hex(inputStream),
                mf.getContentType(),
                FileDataTypeUtil.getDataType(mf.getContentType()).getDesc1(),
                null
        );
        return file;
    }

    /**
     * 构建存储到分布式文件系统的文件名
     *
     * @param fileExtName 文件扩展名
     * @return 文件名
     */
    private String buildFileName(String fileExtName) {
        // 这个格式：2024/10/7/asdnxc.png
        String fileNamePrefix = DateUtil.format(new Date(), "yyyy/MM/dd/");
        String fileName = fileNamePrefix + UUID.fastUUID().toString(true) + StrPool.DOT + fileExtName;
        return fileName;
    }

    /**
     * 上传文件方法，子类实现
     *
     * @param file
     * @return
     */
    public abstract void doUpload(File file, MultipartFile mf);
}
